package com.coderman.utils.enums;


import com.coderman.utils.clazz.ClassUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author fanchunshuai
 * @Date 2019/2/21 09
 * @Description: 扫描当前项目工程包下所有枚举类生成
 * Map<key,value>和Map<value,key>格式的数据结构
 *
 */
public class EnumUtils {

    /**
     * 获取枚举类中的数据以map->k,v的形式返回
     * map.key:是枚举类名
     * map.v.key:是枚举类中属性的第一个值
     * map.v.value:是枚举类中属性的第2->n个值,多个值使用,分隔
     * 如果枚举只有一个属性，则map.v.key = map.v.value
     * 默认采用递归的方式获取packagePath下所有枚举类，
     * 如果packagePath下存在类名相同的枚举类则会发生覆盖的情况。
     * @param packagePath  扫描枚举类的包路径
     * @return 如果出现异常则返回null
     */
    public static Map<String, Map<String,String>> getServiceEnumMap(String packagePath){
        List<Class<?>> classEnumsList =  ClassUtils.getClass(packagePath,true);
        Map<String, Map<String,String>> enumMap = new HashMap<>();
        try {
            for (Class<?> clazz : classEnumsList){
                if(clazz.isEnum()){
                    List<String> fieldList = getEnumFieldList(clazz);
                    Map<String,Method> methodMap = getEnumMethodList(fieldList,clazz);

                    Object[] objects = clazz.getEnumConstants();
                    Map<String,String> enumDataMap = new HashMap<>();
                    for (Object obj : objects){
                        // 3.调用对应方法，得到枚举常量中字段的值
                        List<String> valueList = new ArrayList<>();
                        methodMap.forEach((k,v)->{
                            try {
                                String value = v.invoke(obj).toString();
                                valueList.add(value);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        });
                        String value = "";
                        if(valueList.size() > 2){
                            StringBuilder builder = new StringBuilder();
                            for (int i = 1;i < valueList.size();i ++){
                                builder.append(valueList.get(i)+",");
                            }
                            value = builder.substring(0,builder.length() - 1);
                        }
                        else if(valueList.size() == 2){
                            value = valueList.get(1);
                        }
                        else if(valueList.size() == 1){
                            value = valueList.get(0);
                        }
                        enumDataMap.put(valueList.get(0),value);
                    }
                    enumMap.put(clazz.getSimpleName(),enumDataMap);
                }
            }
            return enumMap;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取枚举类中的数据以map->k,v的形式返回
     * map.key:是枚举类名
     * map.v.key:是枚举类中属性的最后一个值
     * map.v.value:是枚举类中属性的第1->(n-1)个值,多个值使用,分隔
     * 如果枚举只有一个属性，则map.v.key = map.v.value
     * 默认采用递归的方式获取packagePath下所有枚举类，
     * 如果packagePath下存在类名相同的枚举类则会发生覆盖的情况。
     * @param packagePath  扫描枚举类的路径
     * @return 如果出现异常则返回null
     *
     * 与上面的工具方法是相辅相成的
     */
    public static Map<String, Map<String,String>> getServiceConvertEnumMap(String packagePath){
        List<Class<?>> classEnumsList =  ClassUtils.getClass(packagePath,true);
        Map<String, Map<String,String>> convertEnumMap = new HashMap<>();
        try {
            for (Class<?> clazz : classEnumsList){
                if(clazz.isEnum()){
                    List<String> fieldList = getEnumFieldList(clazz);
                    Map<String,Method> methodMap = getEnumMethodList(fieldList,clazz);

                    Object[] objects = clazz.getEnumConstants();
                    Map<String,String> convertenumDataMap = new HashMap<>();
                    for (Object obj : objects){
                        // 3.调用对应方法，得到枚举常量中字段的值
                        List<String> valueList = new ArrayList<>();
                        methodMap.forEach((k,v)->{
                            try {
                                String value = v.invoke(obj).toString();
                                valueList.add(value);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        });
                        String value = "";
                        if(valueList.size() > 2){
                            StringBuilder builder = new StringBuilder();
                            for (int i = 0;i < valueList.size() - 1;i ++){
                                builder.append(valueList.get(i)+",");
                            }
                            value = builder.substring(0,builder.length() - 1);
                        }
                        else if(valueList.size() == 2){
                            value = valueList.get(0);
                        }
                        else if(valueList.size() == 1){
                            value = valueList.get(0);
                        }
                        convertenumDataMap.put(valueList.get(valueList.size() - 1),value);
                    }
                    convertEnumMap.put(clazz.getSimpleName(),convertenumDataMap);
                }
            }
            return convertEnumMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 根据枚举类动态获取枚举类中的变量
     * @param clazz
     * @return
     */
    private static List<String> getEnumFieldList(Class<?> clazz){
        List<String> enumFieldList = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields){
            if(field.isEnumConstant() == false  && !field.getName().startsWith("$")){
                enumFieldList.add(field.getName());
            }
        }
        return enumFieldList;
    }

    /**
     * 根据枚举类动态获取枚举类中的变量
     * @param fieldNameList
     * @param clazz
     * @return
     */
    private static Map<String, Method> getEnumMethodList(List<String> fieldNameList, Class<?> clazz) throws NoSuchMethodException {
        Map<String,Method>  methodList = new HashMap<>();
        for (String fieldName : fieldNameList){
            String methodName = getGetMethodStr(fieldName);
            Method targetMethod = clazz.getMethod(methodName);
            methodList.put(fieldName,targetMethod);
        }
        return methodList;
    }

    /**
     * 获取get方法
     * @param fieldName
     * @return
     */
    private static String getGetMethodStr(String fieldName){
        return "get"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
    }
}
